﻿using Quartz;
using Quartz.Impl.Matchers;
using Quartz.Impl.Triggers;
using QiAdmin.Core.Services.Quartz;
using static Quartz.MisfireInstruction;

namespace QiAdmin.Core.Services
{
    /// <summary>
    /// Quartz帮助类
    /// 一个Job可以被多个Trigger使用,一个Trigger只能使用一个Job
    /// Job停止、删除等会对应操作所有Trigger，Trigger停止、删除只会操作当前对应的Job
    /// JobGroup和TriggerGroup不是一个东西，Group可以更加方便的管理Job和Trigger
    /// </summary>
    public class QuartzFactory
    {
        readonly IScheduler _scheduler;
        public QuartzFactory(IScheduler scheduler)
        {
            _scheduler = scheduler;
        }

        public async Task Add<T>(JobModel jobModel) where T : IJob
        {
            IJobDetail jobDetail = JobBuilder.Create<T>()
              .WithIdentity(jobModel.JobName, jobModel.JobGroup)
              .UsingJobData(jobModel.JobData)
              .Build();


            var triggerBuilder = TriggerBuilder.Create()
               .WithIdentity(jobModel.TriggerName, jobModel.TriggerGroup);
            if (jobModel.StartTime != null)
            {
                triggerBuilder = triggerBuilder.StartAt(new DateTimeOffset(jobModel.StartTime.Value));
            }
            else
            {
                triggerBuilder = triggerBuilder.StartNow();
            }
            if (jobModel.EndTime != null)
            {
                triggerBuilder = triggerBuilder.EndAt(new DateTimeOffset(jobModel.EndTime.Value));
            }

            if (jobModel.IsSimpleSchedule)
            {
                if (jobModel.SimpleRepeatCount > 0)
                {
                    triggerBuilder = triggerBuilder.WithSimpleSchedule(s => s.WithInterval(jobModel.SimpleExpression).WithRepeatCount(jobModel.SimpleRepeatCount));
                }
                else
                {
                    triggerBuilder = triggerBuilder.WithSimpleSchedule(s => s.WithInterval(jobModel.SimpleExpression).RepeatForever());
                }
            }
            else
            {
                if (!CronExpression.IsValidExpression(jobModel.CronExpression))
                {
                    throw new SystemException("表达式配置错误");
                }
                triggerBuilder = triggerBuilder.WithCronSchedule(jobModel.CronExpression);
            }

            ITrigger trigger = triggerBuilder.Build();
            //解决Quartz启动后第一次会立即执行问题解决办法
            ((CronTriggerImpl)trigger).MisfireInstruction = CronTrigger.DoNothing;

            await _scheduler.ScheduleJob(jobDetail, trigger);
        }

        public async Task RemoveJob(JobKey jobKey)
        {
            if (await ExistsJob(jobKey))
            {
                await _scheduler.DeleteJob(jobKey);
            }
        }
        public async Task RemoveTrigger(TriggerKey triggerKey)
        {
            if (await ExistsTrigger(triggerKey))
            {
                await _scheduler.UnscheduleJob(triggerKey);
            }
        }

        public async Task PaushJob(JobKey jobKey)
        {
            if (await ExistsJob(jobKey))
            {
                await _scheduler.PauseJob(jobKey);
            }
        }

        public async Task PaushTrigger(TriggerKey triggerKey)
        {
            if (await ExistsTrigger(triggerKey))
            {
                await _scheduler.PauseTrigger(triggerKey);
            }
        }

        public async Task ResumeJob(JobKey jobKey)
        {
            if (await ExistsJob(jobKey))
            {
                await _scheduler.ResumeJob(jobKey);
            }
        }

        public async Task ResumeTrigger(TriggerKey triggerKey)
        {
            if (await ExistsTrigger(triggerKey))
            {
                await _scheduler.ResumeTrigger(triggerKey);
            }
        }

        public async Task<bool> ExistsJob(JobKey jobKey)
        {
            return await _scheduler.CheckExists(jobKey);
        }
        public async Task<bool> ExistsTrigger(TriggerKey triggerKey)
        {
            var triggers = await _scheduler.GetTrigger(triggerKey);
            return triggers != null;
        }

        public async Task UpdateJob<T>(JobModel jobModel) where T : IJob
        {
            JobKey jobKey = new JobKey(jobModel.JobName, jobModel.JobGroup);
            if (await ExistsJob(jobKey))
            {
                await RemoveJob(jobKey);
            }
            await Add<T>(jobModel);
        }

        public async Task UpdateTrigger<T>(JobModel jobModel) where T : IJob
        {
            TriggerKey triggerKey = new TriggerKey(jobModel.TriggerName, jobModel.TriggerGroup);
            if (await ExistsTrigger(triggerKey))
            {
                await RemoveTrigger(triggerKey);
            }
            await Add<T>(jobModel);
        }

        public async Task<IJobDetail?> GetJob(JobKey jobKey)
        {
            return await _scheduler.GetJobDetail(jobKey);
        }

        public async Task<ITrigger?> GetTrigger(TriggerKey triggerKey)
        {
            return await _scheduler.GetTrigger(triggerKey);
        }

        public async Task<JobModel?> GetJobAndTrigger(JobKey jobKey)
        {
            JobModel jobModel = new JobModel();
            var jobDetail = await _scheduler.GetJobDetail(jobKey);
            if (jobDetail != null)
            {
                jobModel.JobName = jobDetail.Key.Name;
                jobModel.JobGroup = jobDetail.Key.Group;
                jobModel.JobData = jobDetail.JobDataMap;

                var triggers = await _scheduler.GetTriggersOfJob(jobKey);
                var trigger = triggers.First();

                jobModel.TriggerName = trigger.Key.Name;
                jobModel.TriggerGroup = trigger.Key.Group;
                jobModel.StartTime = trigger.StartTimeUtc.UtcDateTime;
                jobModel.EndTime = trigger.EndTimeUtc?.UtcDateTime;

                if (trigger is ISimpleTrigger simple)
                {
                    jobModel.IsSimpleSchedule = true;
                    jobModel.SimpleRepeatCount = simple.RepeatCount;
                    jobModel.SimpleExpression = simple.RepeatInterval;

                }
                else
                {
                    jobModel.IsSimpleSchedule = false;
                    ICronTrigger cron = (ICronTrigger)trigger;
                    jobModel.CronExpression = cron.CronExpressionString;
                }
            }
            return jobModel;
        }

        public async Task<List<JobModel>> GetAll()
        {
            List<JobModel> jobModels = new List<JobModel>();

            // 获取所有作业的 JobKey 列表  
            var jobKeys = await _scheduler.GetJobKeys(GroupMatcher<JobKey>.AnyGroup());
            foreach (var jobKey in jobKeys)
            {
                JobModel jobModel = new JobModel();
                var jobDetail = await _scheduler.GetJobDetail(jobKey);
                if (jobDetail != null)
                {
                    jobModel.JobName = jobDetail.Key.Name;
                    jobModel.JobGroup = jobDetail.Key.Group;
                    jobModel.JobData = jobDetail.JobDataMap;

                    var triggers = await _scheduler.GetTriggersOfJob(jobKey);
                    var trigger = triggers.First();

                    jobModel.TriggerName = trigger.Key.Name;
                    jobModel.TriggerGroup = trigger.Key.Group;
                    jobModel.StartTime = trigger.StartTimeUtc.UtcDateTime;
                    jobModel.EndTime = trigger.EndTimeUtc?.UtcDateTime;

                    if (trigger is ISimpleTrigger simple)
                    {
                        jobModel.IsSimpleSchedule = true;
                        jobModel.SimpleRepeatCount = simple.RepeatCount;
                        jobModel.SimpleExpression = simple.RepeatInterval;

                    }
                    else
                    {
                        jobModel.IsSimpleSchedule = false;
                        ICronTrigger cron = (ICronTrigger)trigger;
                        jobModel.CronExpression = cron.CronExpressionString;
                    }
                    jobModels.Add(jobModel);
                }

            }

            return jobModels;
        }

        public async Task Run(JobKey jobKey)
        {
            if (await ExistsJob(jobKey))
            {
                await _scheduler.TriggerJob(jobKey);
            }

        }

        /// <summary>
        /// 关闭调度器
        /// 要开启只能重新实例化调度器Scheduler,一般情况请勿使用
        /// </summary>
        /// <returns></returns>
        public async Task Shutdown()
        {
            await _scheduler.Shutdown();
        }
        public async Task PauseAll()
        {
            await _scheduler.PauseAll();
        }
        public async Task ResumeAll()
        {
            await _scheduler.ResumeAll();
        }
    }
}
